package com.gitee.magic.core.utils.codec;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.gitee.magic.core.exception.ApplicationException;

/**
 * PBE安全编码组件
 * @author start
 */
public class PbeCoder {

	/**
	 * 支持以下任意一种算法
	 * <pre>
	 * PBEWithMD5AndDES  
	 * PBEWithMD5AndTripleDES  
	 * PBEWithSHA1AndDESede 
	 * PBEWithSHA1AndRC2_40
	 * </pre>
	 */
	public static final String ALGORITHM = "PBEWITHMD5andDES";
	
	public static final int SALTLENGTH=8;

	/**
	 * 盐初始化
	 * @return
	 * @throws Exception
	 */
	public static byte[] initSalt() {
		byte[] salt = new byte[SALTLENGTH];
		Random random = new Random();
		random.nextBytes(salt);
		return salt;
	}

	/**
	 * 转换密钥
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 */
	private static Key getKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		SecretKey secretKey = keyFactory.generateSecret(keySpec);
		return secretKey;
	}

	/**
	 * 加密
	 * @throws NoSuchPaddingException 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 * @throws InvalidAlgorithmParameterException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 */
	public static byte[] encrypt(byte[] data, String password, byte[] salt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
		Key key = getKey(password);
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
		return cipher.doFinal(data);
	}

	/**
	 * 解密
	 * @throws InvalidKeySpecException 
	 * @throws NoSuchAlgorithmException 
	 * @throws NoSuchPaddingException 
	 * @throws InvalidAlgorithmParameterException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 */
	public static byte[] decrypt(byte[] data, String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
		Key key = getKey(password);
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
		return cipher.doFinal(data);
	}
	
	/**
	 * 加密
	 * @param content 明文
	 * @param password	密码
	 * @return
	 */
	public static String encrypt(String content, String password) {
		byte[] sale=PbeCoder.initSalt();
		byte[] encrypt;
		try {
			encrypt = PbeCoder.encrypt(content.getBytes(), password,sale);
		} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeySpecException
				| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
			throw new ApplicationException(e);
		}
		byte[] alldata=new byte[sale.length+encrypt.length];
		System.arraycopy(sale, 0, alldata, 0, sale.length);
		System.arraycopy(encrypt, 0, alldata, sale.length, encrypt.length);
		return Base64.encode(alldata);
	}
	
	/**
	 * 解密
	 * @param content base64加密后的密文
	 * @param password 密码
	 * @return
	 */
	public static String decrypt(String content,String password) {
		byte[] alldata=Base64.decode(content);
		byte[] sale=new byte[SALTLENGTH];
		byte[] encrypt=new byte[alldata.length-sale.length];
		System.arraycopy(alldata, 0, sale, 0, sale.length);
		System.arraycopy(alldata, sale.length, encrypt, 0, encrypt.length);
		try {
			return new String(decrypt(encrypt, password, sale));
		} catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException
				| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
			throw new ApplicationException(e);
		}
	}

	public static void main(String[] args) throws Exception {
		String password="123456";
		String content = "5b3c38830da6ad1b3b8907341e1d6848546ce2b7cd02b0ebf6b99a8ad35b5218";
		String encrypt=encrypt(content,password);
		System.out.println(encrypt);
		System.out.println(decrypt(encrypt, password));
//		String password = System.getenv("JASYPT_ENCRYPTOR_PASSWORD");
//		System.out.println(password);
//		byte[] sale=PBECoder.initSalt();
////		System.out.println(Base64.encode(sale));
//		String encrypt = Base64.encode(PBECoder.encrypt(content.getBytes(), password,sale));
//		System.out.println("密文：" + encrypt);
//		content = new String(PBECoder.decrypt(Base64.decode(encrypt), password,sale));
////    	String content = new String(PBECoder.decrypt("DtowIgtREd6t0wJpP4mJqNNPmakVF8WpmrC5dbLXtCdEh2ettdhVvSo8RrSOB0QGvUDVltfjnI9S3Ue9BFrLH8tpfZP3h9wmZqC4y97/0rs=".getBytes(),password,sale));
//        System.out.println("原文："+content);
	}

}